﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Diagnostics;
using DBWTProject.persistence;
using DBWTProject.models;
using System.Text;
using System.Reflection;
using System.Xml.Linq;
using DBWTProject.route.util;
using System.Globalization;

namespace DBWTProject.route
{
    public partial class CompareRoutes : System.Web.UI.Page
    {

        private IList<Route> _comparingRoutes;

        protected void Page_Load(object sender, EventArgs e)
        {
            User user = (User)Session[Constants.SESSIONVAR_CURRENTUSER];
            if (user == null)
            {//nicht eingeloggt
                Response.Redirect("/");
                return;
            }

            string compareRouteIDs = Request.QueryString["compareRouteIDs"];//Form: 1_6_12
            if (String.IsNullOrEmpty(compareRouteIDs))
            {
                Response.Redirect("/route/MyRoutes.aspx");
                return;
            }

            string[] compareRouteIDsSplit = compareRouteIDs.Split('_');
            _comparingRoutes = RouteDAO.GetRoutes(compareRouteIDsSplit);

            //Vergleichstabelle aufbauen
            grvCompareRoutes.DataSource = _comparingRoutes;
            grvCompareRoutes.DataBind();
        }

        /// <summary>
        /// Erstellt die von Google Visualization genötigte DataTable als JSON-String.
        /// Der Parameter spezifiziert, von welcher Property der Route-Objekt die Werte in die Tabelle eingetragen werden.
        /// (Einsatz von Reflection gegen Codeduplizierung)
        /// </summary>
        /// <param name="propertyName">z.B. "Duration" oder "Distance". s. Propertys von Route</param>
        /// <returns></returns>
        public string GetDataTable(string propertyName)
        {
            CultureInfo cultureInfoUS = new CultureInfo("en-US", false);
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("[");

            //['Characteristic', 'Route1', 'Route2', 'Route3'],
            sb.Append("['Characteristic', ");
            foreach (Route route in _comparingRoutes)
            {
                sb.Append("'");
                sb.Append(route.Name);
                sb.Append("',");
            }
            sb.AppendLine("],");

            //['Total distance', 1000, 400, 800],
            sb.Append("['Routes', ");
            PropertyInfo property = typeof(Route).GetProperty(propertyName);
            foreach (Route route in _comparingRoutes)
            {
                double value = (double)property.GetValue(route, null);
                sb.Append(value.ToString("0.0", cultureInfoUS));
                sb.Append(",");
            }
            sb.AppendLine("]");

            sb.AppendLine("]");
            return sb.ToString();
        }

        /*[['Characteristic', 'Route1', 'Route2', 'Route3'],
           ['Total distance', 1000, 400, 800],
           ['Total duration', 1170, 460],
           ['Elevation covered', 660, 1120],
           ['Mean speed', 1030, 540]]
         * 
         * oder mit customizten Tooltip:
         *   var data = new google.visualization.DataTable();
              data.addColumn('string', 'Game');
              data.addColumn('number', 'Transactions1');
              data.addColumn('number', 'Transactions2');
              data.addColumn({type:'string', role:'tooltip'});
              data.addRows([
                ['2003',  1336060,   3817614, 'Tooltip1'+4063223],
                ['2004',  1538156,   3968305, 'Tooltip2'],
                ['2008',  1901067,   6792087, 'Tooltip3']  
              ]);
         * */

        //s. Doku in ChartUtil.getMergedCoorMatrix() für weitere Infos zu diesen Instanzvar.
        private List<List<Tuple<double, double>>> _heightProfilesList;
        private List<List<Tuple<double, double>>> _speedProfilesList;

        public enum ProfileName {HEIGHT_PROFILE, SPEED_PROFILE, }

        /// <summary>
        /// Erstellt die von Google Visualization genötigte DataTable als JSON-String für den Höhen- o. Geschwindigkeitsvergleich.
        /// </summary>
        /// <param name="profileName">ProfileName.HEIGHT_PROFILE oder ProfileName.SPEED_PROFILE</param>
        /// <returns></returns>
        public string GetDataTableForProfile(ProfileName profileName)
        {
            InitComparisionProfileLists();
            switch (profileName)
            {
                case ProfileName.HEIGHT_PROFILE:
                    return GetDataTableForProfile(_heightProfilesList);
                case ProfileName.SPEED_PROFILE:
                    return GetDataTableForProfile(_speedProfilesList);
                default:
                    throw new ArgumentException("Invalid Profilename:" + profileName);
            }
            
        }

        /// <summary>
        /// Erstellt die DataTable für den Vergleich tatsächlich. Ist generisch und kann fürs
        /// Höhenprofil und Geschwindigkeitsprofil verwendet werden.
        /// </summary>
        /// <returns></returns>
        private string GetDataTableForProfile(List<List<Tuple<double, double>>> profileCompareList)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("[");

            //['Entfernung', 'Höhe Route1', 'Höhe Route2']
            sb.Append("['Distance', ");
            foreach (Route route in _comparingRoutes)
            {
                sb.Append("'");
                sb.Append(route.Name);
                sb.Append("',");
            }
            sb.AppendLine("],");

            SortedDictionary<double, double?[]> mergedCoorMatrix = ChartUtil.GetMergedCoorMatrix(profileCompareList);
            //ChartUtil.printMatrix(mergedCoorMatrix);

            NumberFormatInfo numberFormatUS = new CultureInfo("en-US", false).NumberFormat;
            foreach (KeyValuePair<double, double?[]> entry in mergedCoorMatrix)
            {
                sb.Append("[");
                double?[] yTupels = entry.Value;
                string ys = "";
                foreach (double? y in yTupels)
                {
                    ys += y == null ? "null" : y.Value.ToString("0.0", numberFormatUS);
                    ys += ", ";
                }
                string xkey = entry.Key.ToString("0.0", numberFormatUS);//damit "." separator für nachkommastellen
                sb.Append(xkey + ", " + ys);
                sb.AppendLine("],");
            }
            sb.AppendLine("]");
            return sb.ToString();
        }

        /// <summary>
        /// Da beide Listen in einem Rutsch erstellt werden können, soll es auch bei diesem einem Rutsch bleiben.
        /// Init erfolgt nur, wenn noch kein Init gelaufen ist.
        /// </summary>
        private void InitComparisionProfileLists()
        {
            if (_heightProfilesList == null || _speedProfilesList == null)
            {
                _heightProfilesList = new List<List<Tuple<double, double>>>();
                _speedProfilesList = new List<List<Tuple<double, double>>>();
                foreach (Route route in _comparingRoutes)
                {
                    List<Tuple<double, double>> elevationProfilePoints;
                    List<Tuple<double, double>> speedProfilePoints;
                    ChartUtil.CalculateProfiles(route, out elevationProfilePoints, out speedProfilePoints);

                    _heightProfilesList.Add(elevationProfilePoints);
                    _speedProfilesList.Add(speedProfilePoints);
                }
            }
        }
    }
}